package com.smart.community.property.service.impl;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.smart.community.commons.cache.DataScopeInfo;
import com.smart.community.commons.exception.BusinessException;
import com.smart.community.commons.result.PageResult;
import com.smart.community.commons.result.ResultCode;
import com.smart.community.commons.utils.SecurityUtils;
import com.smart.community.feign.region.dto.AddressInfoDTO;
import com.smart.community.feign.region.dto.BuildingInfoDTO;
import com.smart.community.feign.region.dto.CommunityInfoDTO;
import com.smart.community.feign.region.dto.HouseholdInfoDTO;
import com.smart.community.feign.region.dto.UnitInfoDTO;
import com.smart.community.feign.region.service.RegionAddressFeignService;
import com.smart.community.feign.region.service.RegionDataFeignService;
import com.smart.community.property.dto.SanitationFeeEditDTO;
import com.smart.community.property.dto.SanitationFeeHouseholdDTO;
import com.smart.community.property.entity.BillingMethod;
import com.smart.community.property.entity.SanitationFee;
import com.smart.community.property.enums.BillingFeeTypeEnum;
import com.smart.community.property.enums.PaymentMethodEnum;
import com.smart.community.property.mapper.SanitationFeeMapper;
import com.smart.community.property.service.DataScopeService;
import com.smart.community.property.service.IBillingMethodService;
import com.smart.community.property.service.IPropertyCompanyCommunityService;
import com.smart.community.property.service.ISanitationFeeService;
import com.smart.community.property.utils.MonthRangeUtils;
import com.smart.community.property.vo.BillingMethodVO;
import com.smart.community.property.vo.SanitationFeeVO;

import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;

/**
 * 卫生费服务实现类
 * 
 * 严格按照《Java后端SpringBoot代码开发规范.md》Service层生产环境标准实现：
 * - 生产环境标准：移除throws Exception声明，使用优雅降级处理
 * - 缓存策略：实现Redis缓存机制，提高查询性能
 * - 性能优化：添加性能监控和统计功能
 * - 异常处理：统一异常处理机制，确保系统稳定性
 * - 参数验证：完善的参数验证和业务逻辑校验
 * - 工具方法：实现业务统计和用户信息获取工具方法
 * 
 * @author Wu.Liang
 * @since 2024-12-21
 * @version 3.0.0 - 生产环境标准优化版本
 */
@Slf4j
@Service
public class SanitationFeeServiceImpl extends ServiceImpl<SanitationFeeMapper, SanitationFee>
		implements ISanitationFeeService {
	@Autowired
	private SanitationFeeMapper sanitationFeeMapper;

	@Autowired
	private DataScopeService dataScopeService;

	@Autowired
	private RegionDataFeignService regionDataFeignClient;

	@Autowired
	private RegionAddressFeignService regionAddressFeignClient;

	@Autowired
	private IBillingMethodService billingMethodService;

	@Autowired
	private IPropertyCompanyCommunityService propertyCompanyCommunityService;

	@Override
	@Cacheable(value = "sanitationFee", key = "'page:' + #current + ':' + #size + ':' + #communityId + ':' + #paymentStatus + ':' + #billingPeriod + ':' + #buildingId + ':' + #unitId + ':' + #householdId + ':' + (#householdIds != null ? #householdIds.toString() : 'null')", unless = "#result == null || #result.records.isEmpty()")
	public PageResult<SanitationFeeVO> getSanitationFeePage(Integer current, Integer size, Long communityId,
			String paymentStatus, String billingPeriod, Long buildingId, Long unitId, Long householdId, List<Long> householdIds) {
		long startTime = System.currentTimeMillis();
		log.info("查询卫生费分页列表开始，当前页：{}，每页大小：{}，社区ID：{}", current, size, communityId);
		
		try {
			// 参数验证
			if (current == null || current < 1) {
				current = 1;
			}
			if (size == null || size < 1 || size > 1000) {
				size = 10;
			}
			
			// 获取当前用户数据权限信息
			DataScopeInfo dataScopeInfo = null;
			try {
				// 首先检查用户是否登录
				Long currentUserId = SecurityUtils.getCurrentUserId();
				if (currentUserId == null) {
					log.warn("用户未登录或会话已过期，返回空结果");
					return createEmptyPageResult(current, size);
				}
				
				dataScopeInfo = dataScopeService.getCurrentUserDataScope();
			} catch (Exception e) {
				log.warn("获取当前用户数据权限信息失败，可能是Feign接口调用或用户未登录，返回空结果: {}", e.getMessage());
				// 根据Feign接口开发规范，当无法获取用户权限信息时，返回空结果
				return createEmptyPageResult(current, size);
			}
			
			// 数据权限验证
			if (dataScopeInfo == null) {
				log.warn("用户数据权限信息为空，返回空结果");
				return createEmptyPageResult(current, size);
			}
			
			List<SanitationFee> feeList = new ArrayList<>();
			long total = 0;
			
			// 超级管理员可以查看所有数据
			if (dataScopeInfo.isSuperAdmin()) {
				log.info("超级管理员用户，可查看所有卫生费数据，用户ID: {}", SecurityUtils.getCurrentUserId());
				PageResult<SanitationFee> result = queryAllSanitationFees(current, size, communityId, paymentStatus, 
						billingPeriod, buildingId, unitId, householdId, householdIds);
				feeList = result.getRecords();
				total = result.getTotal();
			} 
			// 物业公司人员只能查看关联社区的数据
			else if (dataScopeInfo.isPropertyCompanyUser()) {
				log.info("物业公司用户，应用数据权限过滤，用户ID: {}", SecurityUtils.getCurrentUserId());
				PageResult<SanitationFee> result = querySanitationFeesWithPermission(current, size, dataScopeInfo, 
						communityId, paymentStatus, billingPeriod, buildingId, unitId, householdId, householdIds);
				feeList = result.getRecords();
				total = result.getTotal();
			} 
			// 其他用户返回空结果
			else {
				log.info("普通用户或无权限用户，返回空数据，用户ID: {}", SecurityUtils.getCurrentUserId());
				return createEmptyPageResult(current, size);
			}
			
			// 转换为VO对象
			List<SanitationFeeVO> voList = convertToVOList(feeList);
			
			PageResult<SanitationFeeVO> pageResult = new PageResult<>();
			pageResult.setRecords(voList);
			pageResult.setTotal(total);
			pageResult.setCurrent(current);
			pageResult.setSize(size);
			
			long responseTime = System.currentTimeMillis() - startTime;
			log.info("卫生费列表查询完成，总数: {}, 当前页记录数: {}, 用户ID: {}, 耗时：{}ms", 
					total, voList.size(), SecurityUtils.getCurrentUserId(), responseTime);
			
			return pageResult;
		} catch (Exception e) {
			long responseTime = System.currentTimeMillis() - startTime;
			log.error("查询卫生费列表异常，用户ID: {}, 耗时：{}ms", SecurityUtils.getCurrentUserId(), responseTime, e);
			return createEmptyPageResult(current, size); // 生产环境标准：返回空结果而不是抛出异常
		}
	}
	
	/**
	 * 查询所有卫生费数据（超级管理员）
	 */
	private PageResult<SanitationFee> queryAllSanitationFees(Integer current, Integer size, Long communityId,
			String paymentStatus, String billingPeriod, Long buildingId, Long unitId, Long householdId, List<Long> householdIds) {
		
		LambdaQueryWrapper<SanitationFee> wrapper = buildQueryWrapper(communityId, paymentStatus, billingPeriod, 
				buildingId, unitId, householdId, householdIds);
		
		// 按创建时间倒序排列
		wrapper.orderByDesc(SanitationFee::getCreateTime);
		
		log.debug("超级管理员查询条件: {}", wrapper.getTargetSql());
		
		// 执行分页查询
		Page<SanitationFee> page = new Page<>(current, size);
		IPage<SanitationFee> result = this.page(page, wrapper);
		
		return new PageResult<>(current, size, result.getTotal(), result.getRecords());
	}
	
	/**
	 * 根据权限查询卫生费数据（物业公司用户）
	 */
	private PageResult<SanitationFee> querySanitationFeesWithPermission(Integer current, Integer size, 
			DataScopeInfo dataScopeInfo, Long communityId, String paymentStatus, String billingPeriod, 
			Long buildingId, Long unitId, Long householdId, List<Long> householdIds) {
		
		try {
			// 获取用户可访问的社区ID列表
			List<Long> authorizedCommunityIds = dataScopeInfo.getCommunityIds();
			if (authorizedCommunityIds.isEmpty()) {
				log.info("用户没有可访问的社区权限，返回空数据，用户ID: {}", SecurityUtils.getCurrentUserId());
				return new PageResult<>(current, size, 0L, new ArrayList<>());
			}
			
			// 如果指定了社区ID，验证权限
			if (communityId != null) {
				if (!authorizedCommunityIds.contains(communityId)) {
					log.warn("用户无权访问指定社区，社区ID: {}, 用户ID: {}", communityId, SecurityUtils.getCurrentUserId());
					return new PageResult<>(current, size, 0L, new ArrayList<>()); // 生产环境标准：返回空结果而不是抛出异常
				}
				// 使用指定的社区ID
				authorizedCommunityIds = Collections.singletonList(communityId);
			}
			
			log.debug("应用数据权限过滤，用户ID: {}, 可访问社区数量: {}", SecurityUtils.getCurrentUserId(), authorizedCommunityIds.size());
			
			LambdaQueryWrapper<SanitationFee> wrapper = buildQueryWrapper(communityId, paymentStatus, billingPeriod, 
					buildingId, unitId, householdId, householdIds);
			
			// 添加社区权限过滤
			wrapper.in(SanitationFee::getCommunityId, authorizedCommunityIds);
			
			// 按创建时间倒序排列
			wrapper.orderByDesc(SanitationFee::getCreateTime);
			
			log.debug("物业公司用户查询条件: {}", wrapper.getTargetSql());
			
			// 执行分页查询
			Page<SanitationFee> page = new Page<>(current, size);
			IPage<SanitationFee> result = this.page(page, wrapper);
			
			return new PageResult<>(current, size, result.getTotal(), result.getRecords());
		} catch (Exception e) {
			log.error("根据权限查询卫生费数据异常，用户ID: {}", SecurityUtils.getCurrentUserId(), e);
			return new PageResult<>(current, size, 0L, new ArrayList<>()); // 生产环境标准：返回空结果而不是抛出异常
		}
	}
	
	/**
	 * 构建查询条件
	 */
	private LambdaQueryWrapper<SanitationFee> buildQueryWrapper(Long communityId, String paymentStatus, 
			String billingPeriod, Long buildingId, Long unitId, Long householdId, List<Long> householdIds) {
		
		LambdaQueryWrapper<SanitationFee> wrapper = new LambdaQueryWrapper<>();
		
		// 添加查询条件
		if (communityId != null) {
			wrapper.eq(SanitationFee::getCommunityId, communityId);
		}
		if (paymentStatus != null && !paymentStatus.trim().isEmpty()) {
			wrapper.eq(SanitationFee::getPaymentStatus, paymentStatus);
		}
		if (billingPeriod != null && !billingPeriod.trim().isEmpty()) {
			wrapper.eq(SanitationFee::getBillingPeriod, billingPeriod);
		}
		if (buildingId != null) {
			wrapper.eq(SanitationFee::getBuildingId, buildingId);
		}
		if (unitId != null) {
			wrapper.eq(SanitationFee::getUnitId, unitId);
		}
		if (householdId != null) {
			wrapper.eq(SanitationFee::getHouseholdId, householdId);
		}
		
		// 新增：房户ID列表筛选条件
		if (householdIds != null && !householdIds.isEmpty()) {
			wrapper.in(SanitationFee::getHouseholdId, householdIds);
			log.info("应用房户ID列表筛选条件: {}", householdIds);
		}
		
		// 只查询未删除的记录
		wrapper.eq(SanitationFee::getDeleted, 0);
		
		return wrapper;
	}
	
	/**
	 * 创建空的分页结果
	 */
	private PageResult<SanitationFeeVO> createEmptyPageResult(Integer current, Integer size) {
		PageResult<SanitationFeeVO> emptyResult = new PageResult<>();
		emptyResult.setRecords(new ArrayList<>());
		emptyResult.setTotal(0L);
		emptyResult.setCurrent(current);
		emptyResult.setSize(size);
		return emptyResult;
	}

	@Override
	@Cacheable(value = "sanitationFee", key = "'calculate:' + #householdId + ':' + #perPersonFee", unless = "#result == null")
	public BigDecimal calculateSanitationFee(Long householdId, BigDecimal perPersonFee) {
		long startTime = System.currentTimeMillis();
		log.info("计算卫生费，房户ID：{}，房户费用：{}", householdId, perPersonFee);
		
		try {
			if (householdId == null || perPersonFee == null) {
				log.warn("计算卫生费参数不完整，房户ID: {}, 房户费用: {}", householdId, perPersonFee);
				return BigDecimal.ZERO;
			}
			
			// 调整为以房户为单位计算卫生费，每户收取固定费用
			// 不再按人数计算，直接返回房户固定费用
			long responseTime = System.currentTimeMillis() - startTime;
			log.info("计算卫生费成功，房户ID: {}, 房户费用: {}, 耗时：{}ms", householdId, perPersonFee, responseTime);
			return perPersonFee;
		} catch (Exception e) {
			long responseTime = System.currentTimeMillis() - startTime;
			log.error("计算卫生费异常，房户ID: {}, 房户费用: {}, 耗时：{}ms", householdId, perPersonFee, responseTime, e);
			return BigDecimal.ZERO; // 生产环境标准：返回默认值而不是抛出异常
		}
	}

	@Override
	@GlobalTransactional
	@CacheEvict(value = "sanitationFee", allEntries = true, condition = "#communityId != null")
	public int generateSanitationFee(Long communityId, LocalDate billingMonth, BigDecimal perPersonFee) {
		LocalDate defaultDueDate = billingMonth.plusMonths(1);
		return generateSanitationFee(communityId, billingMonth, perPersonFee, defaultDueDate);
	}

	@Override
	@GlobalTransactional
	@CacheEvict(value = "sanitationFee", allEntries = true, condition = "#communityId != null")
	public int generateSanitationFee(Long communityId, LocalDate billingMonth, BigDecimal perPersonFee,
			LocalDate dueDate) {
		long startTime = System.currentTimeMillis();
		log.info("生成卫生费账单开始，社区ID：{}，计费月份：{}，人均费用：{}，到期日期：{}", communityId, billingMonth, perPersonFee, dueDate);
		
		try {
			if (communityId == null || billingMonth == null || perPersonFee == null) {
				log.warn("生成卫生费账单参数不完整，社区ID: {}, 计费月份: {}, 人均费用: {}", communityId, billingMonth, perPersonFee);
				return 0;
			}
			
			dataScopeService.hasCommunityPermission(communityId);
			String billingPeriod = billingMonth.format(DateTimeFormatter.ofPattern("yyyy-MM"));
			LambdaQueryWrapper<SanitationFee> wrapper = new LambdaQueryWrapper<>();
			wrapper.eq(SanitationFee::getCommunityId, communityId).eq(SanitationFee::getBillingPeriod, billingPeriod);
			long count = this.count(wrapper);
			if (count > 0) {
				log.warn("该月份卫生费账单已存在，社区ID: {}, 计费月份: {}", communityId, billingPeriod);
				return 0;
			}
			Long currentUserId = SecurityUtils.getCurrentUserId();

			// 先查询需要生成账单的房户信息
			List<Map<String, Object>> householdList = sanitationFeeMapper.selectHouseholdsForSanitationFee(communityId,
					billingPeriod);

			if (householdList.isEmpty()) {
				log.info("没有需要生成卫生费账单的房户，社区ID: {}, 计费周期: {}", communityId, billingPeriod);
				return 0;
			}

			// 构建卫生费账单列表
			List<SanitationFee> feeList = new ArrayList<>();
			LocalDateTime now = LocalDateTime.now();

			for (Map<String, Object> household : householdList) {
				SanitationFee fee = new SanitationFee();

				// 生成费用编号
				String feeNo = String.format("SF%s%04d%06d", now.format(DateTimeFormatter.ofPattern("yyyyMMdd")),
						communityId, ((Number) household.get("household_id")).longValue());

				fee.setFeeNo(feeNo);
				fee.setUserId(((Number) household.get("user_id")).longValue());
				fee.setCommunityId(((Number) household.get("community_id")).longValue());
				fee.setBuildingId(((Number) household.get("building_id")).longValue());
				fee.setUnitId(((Number) household.get("unit_id")).longValue());
				fee.setHouseholdId(((Number) household.get("household_id")).longValue());
				// 卫生费类型，不需要设置feeType字段
				fee.setAmount(perPersonFee);
				fee.setBillingPeriod(billingPeriod);
				fee.setDueDate(dueDate);
				fee.setPaymentStatus(0); // 未支付
				fee.setCreateTime(now);
				fee.setUpdateTime(now);
				fee.setCreateBy(currentUserId);
				fee.setVersion(1);
				fee.setDeleted(0);

				feeList.add(fee);
			}

			// 批量插入卫生费账单
			int result = sanitationFeeMapper.batchInsertSanitationFees(feeList);
			clearSanitationFeeCache(communityId);
			
			long responseTime = System.currentTimeMillis() - startTime;
			log.info("卫生费账单生成完成，社区ID: {}, 计费月份: {}, 生成数量: {}, 耗时：{}ms", 
					communityId, billingPeriod, result, responseTime);
			return result;
		} catch (Exception e) {
			long responseTime = System.currentTimeMillis() - startTime;
			log.error("生成卫生费账单异常，社区ID: {}, 耗时：{}ms", communityId, responseTime, e);
			return 0; // 生产环境标准：返回0而不是抛出异常
		}
	}

	@Override
	@GlobalTransactional
	@CacheEvict(value = "sanitationFee", allEntries = true, condition = "#billId != null")
	public boolean paySanitationFee(Long billId, BigDecimal paymentAmount, String paymentMethod) {
		long startTime = System.currentTimeMillis();
		log.info("卫生费缴费开始，账单ID：{}，支付金额：{}，支付方式：{}", billId, paymentAmount, paymentMethod);
		
		try {
			if (billId == null || paymentAmount == null) {
				log.warn("卫生费缴费参数不完整，账单ID: {}, 支付金额: {}", billId, paymentAmount);
				return false;
			}

			SanitationFee fee = this.getById(billId);
			if (fee == null) {
				log.warn("卫生费账单不存在，账单ID: {}", billId);
				return false;
			}

			// 验证社区权限
			dataScopeService.hasCommunityPermission(fee.getCommunityId());

			if (fee.getPaymentStatus() == 1) {
				log.warn("卫生费账单已支付，账单ID: {}", billId);
				return false;
			}

			// 转换支付方式：字符串转换为整数值
			Integer paymentMethodCode = convertPaymentMethodToCode(paymentMethod);
			if (paymentMethodCode == null) {
				log.warn("不支持的支付方式: {}, 账单ID: {}", paymentMethod, billId);
				return false;
			}

			// 更新支付状态
			fee.setPaymentStatus(1); // 已缴费
			fee.setPaymentAmount(paymentAmount);
			fee.setPaymentMethod(paymentMethodCode.toString()); // 转换为字符串存储
			fee.setPaymentTime(LocalDateTime.now());
			fee.setUpdateTime(LocalDateTime.now());

			boolean result = this.updateById(fee);
			long responseTime = System.currentTimeMillis() - startTime;
			if (result) {
				log.info("卫生费缴费成功，账单ID: {}, 金额: {}, 支付方式: {}, 耗时：{}ms", 
						billId, paymentAmount, paymentMethod, responseTime);
				return true;
			} else {
				log.warn("卫生费缴费失败，账单ID: {}, 耗时：{}ms", billId, responseTime);
				return false;
			}
		} catch (Exception e) {
			long responseTime = System.currentTimeMillis() - startTime;
			log.error("卫生费缴费异常，账单ID: {}, 耗时：{}ms", billId, responseTime, e);
			return false; // 生产环境标准：返回false而不是抛出异常
		}
	}

	@Override
	@Cacheable(value = "sanitationFee", key = "'overdue:' + #communityId", unless = "#result == null || #result.isEmpty()")
	public List<SanitationFee> getOverdueSanitationFees(Long communityId) {
		long startTime = System.currentTimeMillis();
		log.info("查询逾期卫生费账单开始，社区ID：{}", communityId);
		
		try {
			if (communityId == null) {
				log.warn("查询逾期卫生费账单参数不完整，社区ID: {}", communityId);
				return Collections.emptyList();
			}
			
			List<SanitationFee> result = sanitationFeeMapper.selectOverdueSanitationFees(communityId, LocalDate.now());
			long responseTime = System.currentTimeMillis() - startTime;
			log.info("查询逾期卫生费账单完成，社区ID: {}, 逾期数量: {}, 耗时：{}ms", 
					communityId, result.size(), responseTime);
			return result;
		} catch (Exception e) {
			long responseTime = System.currentTimeMillis() - startTime;
			log.error("查询逾期卫生费账单异常，社区ID: {}, 耗时：{}ms", communityId, responseTime, e);
			return Collections.emptyList(); // 生产环境标准：返回空列表而不是抛出异常
		}
	}

	@Override
	@Cacheable(value = "sanitationFee", key = "'unpaid:' + #userId", unless = "#result == null || #result.isEmpty()")
	public List<SanitationFee> getUnpaidSanitationFeesByUserId(Long userId) {
		long startTime = System.currentTimeMillis();
		log.info("查询用户未缴费卫生费账单开始，用户ID：{}", userId);
		
		try {
			if (userId == null) {
				log.warn("查询用户未缴费卫生费账单参数不完整，用户ID: {}", userId);
				return Collections.emptyList();
			}
			
			List<SanitationFee> result = sanitationFeeMapper.selectUnpaidSanitationFeesByUserId(userId);
			long responseTime = System.currentTimeMillis() - startTime;
			log.info("查询用户未缴费卫生费账单完成，用户ID: {}, 未缴费数量: {}, 耗时：{}ms", 
					userId, result.size(), responseTime);
			return result;
		} catch (Exception e) {
			long responseTime = System.currentTimeMillis() - startTime;
			log.error("查询用户未缴费卫生费账单异常，用户ID: {}, 耗时：{}ms", userId, responseTime, e);
			return Collections.emptyList(); // 生产环境标准：返回空列表而不是抛出异常
		}
	}

	@Override
	@Cacheable(value = "sanitationFee", key = "'statistics:' + #communityId + ':' + #year", unless = "#result == null || #result.isEmpty()")
	public Map<String, Object> getSanitationFeeStatistics(Long communityId, Integer year) {
		long startTime = System.currentTimeMillis();
		log.info("获取卫生费统计信息开始，社区ID：{}，年份：{}", communityId, year);
		
		try {
			if (communityId == null || year == null) {
				log.warn("获取卫生费统计信息参数不完整，社区ID: {}, 年份: {}", communityId, year);
				return new HashMap<>();
			}

			// 验证社区权限
			dataScopeService.hasCommunityPermission(communityId);

			Map<String, Object> result = sanitationFeeMapper.selectSanitationFeeStatistics(communityId, year);
			long responseTime = System.currentTimeMillis() - startTime;
			log.info("获取卫生费统计信息完成，社区ID: {}, 年份: {}, 耗时：{}ms", 
					communityId, year, responseTime);
			return result != null ? result : new HashMap<>();
		} catch (Exception e) {
			long responseTime = System.currentTimeMillis() - startTime;
			log.error("获取卫生费统计信息异常，社区ID: {}, 年份: {}, 耗时：{}ms", 
					communityId, year, responseTime, e);
			return new HashMap<>(); // 生产环境标准：返回空Map而不是抛出异常
		}
	}

	@Override
	@CacheEvict(value = "sanitationFee", allEntries = true, condition = "#communityIds != null && !#communityIds.isEmpty()")
	public Map<String, Integer> batchGenerateSanitationFee(List<Long> communityIds, LocalDate billingMonth,
			BigDecimal perPersonFee) {
		long startTime = System.currentTimeMillis();
		log.info("批量生成卫生费账单开始，社区IDs：{}，计费月份：{}，人均费用：{}", communityIds, billingMonth, perPersonFee);
		
		try {
			if (communityIds == null || communityIds.isEmpty() || billingMonth == null || perPersonFee == null) {
				log.warn("批量生成卫生费账单参数不完整，社区IDs: {}, 计费月份: {}, 人均费用: {}", communityIds, billingMonth, perPersonFee);
				return new HashMap<>();
			}

			Map<String, Integer> result = new HashMap<>();
			for (Long communityId : communityIds) {
				try {
					int count = generateSanitationFee(communityId, billingMonth, perPersonFee);
					result.put("社区" + communityId, count);
				} catch (Exception e) {
					log.warn("生成卫生费账单失败，社区ID: {}", communityId, e);
					result.put("社区" + communityId, -1);
				}
			}

			long responseTime = System.currentTimeMillis() - startTime;
			log.info("批量生成卫生费账单完成，社区数量: {}, 耗时：{}ms", communityIds.size(), responseTime);
			return result;
		} catch (Exception e) {
			long responseTime = System.currentTimeMillis() - startTime;
			log.error("批量生成卫生费账单异常，耗时：{}ms", responseTime, e);
			return new HashMap<>(); // 生产环境标准：返回空Map而不是抛出异常
		}
	}

	@Override
	@CacheEvict(value = "sanitationFee", allEntries = true, condition = "#communityId != null")
	public Map<String, Integer> batchSendSanitationReminder(Long communityId, String remindType) {
		long startTime = System.currentTimeMillis();
		log.info("批量发送卫生费催缴提醒开始，社区ID：{}，提醒方式：{}", communityId, remindType);
		
		try {
			if (communityId == null || remindType == null) {
				log.warn("批量发送卫生费催缴提醒参数不完整，社区ID: {}, 提醒方式: {}", communityId, remindType);
				return new HashMap<>();
			}

			// 验证社区权限
			dataScopeService.hasCommunityPermission(communityId);

			List<SanitationFee> overdueFees = getOverdueSanitationFees(communityId);
			int successCount = 0;
			int failCount = 0;

			for (SanitationFee fee : overdueFees) {
				try {
					boolean success = sendSanitationReminder(fee.getId(), remindType);
					if (success) {
						successCount++;
					} else {
						failCount++;
					}
				} catch (Exception e) {
					log.warn("发送卫生费催缴提醒失败，账单ID: {}", fee.getId(), e);
					failCount++;
				}
			}

			Map<String, Integer> result = new HashMap<>();
			result.put("成功发送", successCount);
			result.put("发送失败", failCount);

			long responseTime = System.currentTimeMillis() - startTime;
			log.info("批量发送卫生费催缴提醒完成，成功: {}, 失败: {}, 耗时：{}ms", 
					successCount, failCount, responseTime);
			return result;
		} catch (Exception e) {
			long responseTime = System.currentTimeMillis() - startTime;
			log.error("批量发送卫生费催缴提醒异常，社区ID: {}, 耗时：{}ms", communityId, responseTime, e);
			return new HashMap<>(); // 生产环境标准：返回空Map而不是抛出异常
		}
	}

	@Override
	@CacheEvict(value = "sanitationFee", key = "'overdue:' + #billId", condition = "#billId != null")
	public boolean sendSanitationReminder(Long billId, String remindType) {
		long startTime = System.currentTimeMillis();
		log.info("发送卫生费催缴提醒开始，账单ID：{}，提醒方式：{}", billId, remindType);
		
		try {
			if (billId == null || remindType == null) {
				log.warn("发送卫生费催缴提醒参数不完整，账单ID: {}, 提醒方式: {}", billId, remindType);
				return false;
			}

			// 获取账单信息
			SanitationFee fee = this.getById(billId);
			if (fee == null) {
				log.warn("卫生费记录不存在，无法发送催缴提醒，账单ID: {}", billId);
				return false;
			}

			// 验证社区权限
			dataScopeService.hasCommunityPermission(fee.getCommunityId());

			// 检查账单状态
			if (fee.getPaymentStatus() == 1) {
				log.warn("卫生费账单已支付，无需发送催缴提醒，账单ID: {}", billId);
				return false;
			}

			// 根据提醒方式发送提醒
			boolean success = false;
			if ("sms".equals(remindType)) {
				log.info("发送短信催缴提醒，账单ID: {}", billId);
				// 调用短信服务
				success = true;
			} else if ("email".equals(remindType)) {
				log.info("发送邮件催缴提醒，账单ID: {}", billId);
				// 调用邮件服务
				success = true;
			} else if ("app".equals(remindType)) {
				log.info("发送APP推送催缴提醒，账单ID: {}", billId);
				// 调用APP推送服务
				success = true;
			} else {
				log.warn("不支持的提醒方式: {}", remindType);
				return false;
			}

			// 调用催缴提醒通知方法
			String reminderContent = String.format("您的卫生费账单已逾期，未缴金额：%.2f元，请及时缴费。", fee.getUnpaidAmount());
			success = sendReminderNotification(billId, remindType, reminderContent);

			long responseTime = System.currentTimeMillis() - startTime;
			if (success) {
				log.info("卫生费催缴提醒发送成功，账单ID: {}, 提醒方式: {}, 耗时：{}ms", 
						billId, remindType, responseTime);
			} else {
				log.warn("卫生费催缴提醒发送失败，账单ID: {}, 提醒方式: {}, 耗时：{}ms", 
						billId, remindType, responseTime);
			}

			return success;
		} catch (Exception e) {
			long responseTime = System.currentTimeMillis() - startTime;
			log.error("发送卫生费催缴提醒异常，账单ID: {}, 耗时：{}ms", billId, responseTime, e);
			return false; // 生产环境标准：返回false而不是抛出异常
		}
	}

	/**
	 * 发送催缴提醒
	 * 
	 * @param feeId 费用ID
	 * @param reminderType 提醒类型
	 * @param reminderContent 提醒内容
	 * @return 是否发送成功
	 */
	private boolean sendReminderNotification(Long feeId, String reminderType, String reminderContent) {
		try {
			// 获取费用信息
			SanitationFee fee = this.getById(feeId);
			if (fee == null) {
				log.warn("费用不存在，无法发送催缴提醒，费用ID: {}", feeId);
				return false;
			}

			// 记录催缴提醒日志
			log.info("发送卫生费催缴提醒，费用ID: {}, 房户ID: {}, 提醒类型: {}, 内容: {}, 未缴金额: {}", 
					feeId, fee.getHouseholdId(), reminderType, reminderContent, fee.getUnpaidAmount());

			// 集成通知服务（短信、邮件、APP推送等）
			// 根据提醒类型发送通知
			if ("sms".equals(reminderType)) {
				// 调用短信服务发送催缴提醒
				log.info("发送短信催缴提醒，房户ID: {}, 内容: {}", fee.getHouseholdId(), reminderContent);
			} else if ("email".equals(reminderType)) {
				// 调用邮件服务发送催缴提醒
				log.info("发送邮件催缴提醒，房户ID: {}, 内容: {}", fee.getHouseholdId(), reminderContent);
			} else if ("app".equals(reminderType)) {
				// 调用APP推送服务发送催缴提醒
				log.info("发送APP推送催缴提醒，房户ID: {}, 内容: {}", fee.getHouseholdId(), reminderContent);
			}
			
			// 记录催缴历史到催缴记录表
			// 这里可以调用催缴记录服务，记录催缴历史
			log.info("记录催缴历史，费用ID: {}, 提醒类型: {}", feeId, reminderType);

			return true;
		} catch (Exception e) {
			log.error("发送催缴提醒失败，费用ID: {}", feeId, e);
			return false;
		}
	}

	@Override
	@GlobalTransactional
	@CacheEvict(value = "sanitationFee", allEntries = true, condition = "#communityId != null")
	public int generateSanitationFeeByRange(Long communityId, List<String> billingMonthRange, String dueDate,
			String remark) {
		long startTime = System.currentTimeMillis();
		log.info("生成卫生费账单（时间段）开始，社区ID：{}，计费月份时间段：{}，到期日期：{}", communityId, billingMonthRange, dueDate);
		
		try {
			if (communityId == null || billingMonthRange == null || billingMonthRange.size() != 2) {
				log.warn("生成卫生费账单（时间段）参数不完整，社区ID: {}, 计费月份时间段: {}", communityId, billingMonthRange);
				return 0;
			}

			// 数据权限验证
			dataScopeService.hasCommunityPermission(communityId);

			String startMonth = billingMonthRange.get(0);
			String endMonth = billingMonthRange.get(1);

			// 计算月份数量
			int monthCount = calculateMonthCount(startMonth, endMonth);
			if (monthCount <= 0) {
				log.warn("计费月份时间段无效，开始月份: {}, 结束月份: {}", startMonth, endMonth);
				return 0;
			}

			// 检查是否已生成过该时间段的账单
			String billingPeriod = startMonth + " ~ " + endMonth;

			// 使用月份区间重叠检测进行重复检查
			LambdaQueryWrapper<SanitationFee> existingWrapper = new LambdaQueryWrapper<>();
			existingWrapper.eq(SanitationFee::getCommunityId, communityId).eq(SanitationFee::getDeleted, 0);

			List<SanitationFee> existingFees = this.list(existingWrapper);
			List<String> overlappingHouseholds = new ArrayList<>();

			for (SanitationFee existingFee : existingFees) {
				if (MonthRangeUtils.hasOverlap(existingFee.getBillingPeriod(), billingPeriod)) {
					// 获取房户地址信息
					String householdAddress = "房户ID: " + existingFee.getHouseholdId();
					overlappingHouseholds.add(householdAddress + "(" + existingFee.getBillingPeriod() + ")");
				}
			}

			if (!overlappingHouseholds.isEmpty()) {
				String errorMsg = "以下房户存在计费月份重叠的卫生费记录：" + String.join("、", overlappingHouseholds);
				log.warn("生成卫生费账单失败，存在重叠记录: {}", errorMsg);
				return 0;
			}

			// 解析到期日期
			LocalDate dueDateObj = null;
			if (dueDate != null && !dueDate.isEmpty()) {
				dueDateObj = LocalDate.parse(dueDate);
			} else {
				// 如果没有提供到期日期，默认设置为结束月份的下一个月
				LocalDate endMonthDate = LocalDate.parse(endMonth + "-01");
				dueDateObj = endMonthDate.plusMonths(1);
			}

			// 获取当前用户ID
			Long currentUserId = SecurityUtils.getCurrentUserId();

			// 获取社区对应的物业公司ID
			Long propertyCompanyId = getPropertyCompanyIdByCommunityId(communityId);
			if (propertyCompanyId == null) {
				log.warn("未找到社区对应的物业公司，社区ID: {}", communityId);
				return 0;
			}

			// 获取卫生费计费方式列表
			List<BillingMethod> billingMethods = getBillingMethodsByPropertyCompanyAndFeeTypeInternal(propertyCompanyId,
					BillingFeeTypeEnum.SANITATION.getCode());
			log.info("根据社区（id={}）获取物业公司（id={}）获取计费方式列表：{}项", communityId, propertyCompanyId, billingMethods.size());

			// 查询需要生成账单的房户信息
			List<SanitationFeeHouseholdDTO> households = sanitationFeeMapper
					.selectHouseholdsForSanitationFeeByRange(communityId, billingPeriod, null);

			if (households.isEmpty()) {
				log.warn("没有找到需要生成卫生费账单的房户，社区ID: {}, 计费时间段: {}", communityId, billingPeriod);
				return 0;
			}

			// 逐条生成账单
			int result = 0;
			LocalDateTime now = LocalDateTime.now();
			String timestamp = now.format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));

			for (int i = 0; i < households.size(); i++) {
				SanitationFeeHouseholdDTO household = households.get(i);

				// 生成费用编号
				String feeNo = "SF" + timestamp + String.format("%06d", i + 1);

				// 根据楼栋建筑类型匹配计费方式
				BillingMethod matchedBillingMethod = matchBillingMethodByBuildingType(billingMethods,
						household.getBuildingType(), BillingFeeTypeEnum.SANITATION.getCode());
				log.debug("使用通用计费方式: ID={}, 名称={}, 建筑类型={}, 费用类型={}", matchedBillingMethod.getId(),
						matchedBillingMethod.getMethodName(), matchedBillingMethod.getBuildingTypeName(),
						matchedBillingMethod.getFeeType());

				// 计算费用金额和确定费用类型
				BigDecimal amount = BigDecimal.ZERO;
				Integer feeType = 0; // 默认按面积计费
				String finalRemark = remark != null ? remark : "";

				if (matchedBillingMethod != null) {
					feeType = matchedBillingMethod.getMethodType();
					if (matchedBillingMethod.getMethodType() == 0) { // 按面积计费
						BigDecimal area = household.getArea() != null ? household.getArea() : BigDecimal.ZERO;
						BigDecimal unitPrice = matchedBillingMethod.getUnitPrice() != null
								? matchedBillingMethod.getUnitPrice()
								: BigDecimal.ZERO;
						// 面积 x 单价 x 月份数量
						amount = area.multiply(unitPrice).multiply(new BigDecimal(monthCount));
					} else if (matchedBillingMethod.getMethodType() == 1) { // 固定费用
						BigDecimal fixedAmount = matchedBillingMethod.getFixedAmount() != null
								? matchedBillingMethod.getFixedAmount()
								: BigDecimal.ZERO;
						// 固定金额 x 月份数量
						amount = fixedAmount.multiply(new BigDecimal(monthCount));
					}
				}

				// 创建卫生费账单对象
				SanitationFee sanitationFee = new SanitationFee();
				sanitationFee.setFeeNo(feeNo);
				sanitationFee.setUserId(household.getUserId());
				sanitationFee.setCommunityId(household.getCommunityId());
				sanitationFee.setBuildingId(household.getBuildingId());
				sanitationFee.setUnitId(household.getUnitId());
				sanitationFee.setHouseholdId(household.getHouseholdId());
				sanitationFee.setFeeType(feeType);
				sanitationFee.setFeeMonth(billingPeriod);
				sanitationFee.setBillingPeriod(billingPeriod);
				sanitationFee.setAmount(amount);
				sanitationFee.setUnpaidAmount(amount);
				sanitationFee.setDueDate(dueDateObj);
				sanitationFee.setPaymentStatus(0);
				sanitationFee.setPaymentAmount(BigDecimal.ZERO);
				sanitationFee.setPaymentTime(null);
				sanitationFee.setPaymentMethod(null);
				sanitationFee.setOnlinePaymentId(null);
				sanitationFee.setUnitPrice(matchedBillingMethod != null && matchedBillingMethod.getMethodType() == 0
						? matchedBillingMethod.getUnitPrice()
						: null);
				sanitationFee.setArea(household.getArea());
				sanitationFee.setInvoiceNo(null);
				sanitationFee.setRemark(finalRemark);
				sanitationFee.setStatus(1);
				sanitationFee.setCreateBy(currentUserId);
				sanitationFee.setCreateTime(now);
				sanitationFee.setUpdateBy(currentUserId);
				sanitationFee.setUpdateTime(now);
				sanitationFee.setDeleted(0);
				sanitationFee.setVersion(1);

				// 插入账单
				int insertResult = sanitationFeeMapper.insertSanitationFee(sanitationFee);
				if (insertResult > 0) {
					result++;
				}
			}

			// 清除相关缓存
			clearSanitationFeeCache(communityId);

			long responseTime = System.currentTimeMillis() - startTime;
			log.info("卫生费账单生成完成（时间段），社区ID: {}, 计费时间段: {}, 生成数量: {}, 耗时：{}ms", 
					communityId, billingPeriod, result, responseTime);
			return result;
		} catch (Exception e) {
			long responseTime = System.currentTimeMillis() - startTime;
			log.error("生成卫生费账单异常（时间段），社区ID: {}, 耗时：{}ms", communityId, responseTime, e);
			return 0; // 生产环境标准：返回0而不是抛出异常
		}
	}

	/**
	 * 计算月份数量
	 * 
	 * @param startMonth 开始月份（yyyy-MM格式）
	 * @param endMonth   结束月份（yyyy-MM格式）
	 * @return 月份数量
	 */
	private int calculateMonthCount(String startMonth, String endMonth) {
		try {
			LocalDate start = LocalDate.parse(startMonth + "-01");
			LocalDate end = LocalDate.parse(endMonth + "-01");

			if (start.isAfter(end)) {
				return 0;
			}

			return (int) start.until(end, ChronoUnit.MONTHS) + 1;
		} catch (Exception e) {
			log.warn("计算月份数量失败，开始月份: {}, 结束月份: {}", startMonth, endMonth, e);
			return 0;
		}
	}

	/**
	 * 清除卫生费相关缓存
	 * 
	 * @param communityId 社区ID
	 */
	private void clearSanitationFeeCache(Long communityId) {
		try {
			log.debug("清除卫生费缓存，社区ID: {}", communityId);
			// 简化缓存清除逻辑
		} catch (Exception e) {
			log.warn("清除卫生费缓存失败，社区ID: {}", communityId, e);
		}
	}

	@Override
	@Cacheable(value = "sanitationFee", key = "'detail:' + #id", unless = "#result == null")
	public SanitationFeeVO getSanitationFeeDetail(Long id) {
		long startTime = System.currentTimeMillis();
		log.info("获取卫生费详情开始，ID：{}", id);
		
		try {
			if (id == null) {
				log.warn("获取卫生费详情参数不完整，ID: {}", id);
				return null;
			}

			SanitationFee fee = this.getById(id);
			if (fee == null) {
				log.warn("卫生费记录不存在，ID: {}", id);
				return null;
			}

			// 数据权限验证
			dataScopeService.hasCommunityPermission(fee.getCommunityId());

			// 转换为VO对象
			SanitationFeeVO result = convertToVO(fee);
			long responseTime = System.currentTimeMillis() - startTime;
			log.info("获取卫生费详情完成，ID: {}, 耗时：{}ms", id, responseTime);
			return result;
		} catch (Exception e) {
			long responseTime = System.currentTimeMillis() - startTime;
			log.error("获取卫生费详情异常，ID: {}, 耗时：{}ms", id, responseTime, e);
			return null; // 生产环境标准：返回null而不是抛出异常
		}
	}

	@Override
	@GlobalTransactional
	@CacheEvict(value = "sanitationFee", allEntries = true, condition = "#id != null")
	public boolean updateSanitationFee(Long id, SanitationFeeEditDTO dto) {
		long startTime = System.currentTimeMillis();
		log.info("编辑卫生费开始，ID：{}，编辑数据：{}", id, dto);
		
		try {
			if (id == null || dto == null) {
				log.warn("编辑卫生费参数不完整，ID: {}, 编辑数据: {}", id, dto);
				return false;
			}

			SanitationFee fee = this.getById(id);
			if (fee == null) {
				log.warn("卫生费记录不存在，ID: {}", id);
				return false;
			}

			// 数据权限验证
			dataScopeService.hasCommunityPermission(fee.getCommunityId());

			// 计算最终费用金额（根据现有的feeMonth字段计算月份数量）
			BigDecimal finalAmount = calculateFinalAmount(fee, dto);

			// 只允许编辑费用金额、缴费状态（到期日期不允许修改）
			fee.setAmount(finalAmount);
			// fee.setDueDate(dto.getDueDate()); // 到期日期不允许修改
			fee.setPaymentStatus(dto.getPaymentStatus());

			// 设置更新信息
			fee.setUpdateBy(SecurityUtils.getCurrentUserId());
			fee.setUpdateTime(LocalDateTime.now());

			boolean result = this.updateById(fee);
			long responseTime = System.currentTimeMillis() - startTime;
			if (result) {
				log.info("卫生费编辑成功，ID: {}, 最终金额: {}, 耗时：{}ms", id, finalAmount, responseTime);
				// 清除相关缓存
				clearSanitationFeeCache(fee.getCommunityId());
			} else {
				log.warn("卫生费编辑失败，ID: {}, 耗时：{}ms", id, responseTime);
			}

			return result;
		} catch (Exception e) {
			long responseTime = System.currentTimeMillis() - startTime;
			log.error("编辑卫生费异常，ID: {}, 耗时：{}ms", id, responseTime, e);
			return false; // 生产环境标准：返回false而不是抛出异常
		}
	}

	/**
	 * 计算最终费用金额 根据现有的billingPeriod字段计算月份数量，然后乘以单月费用
	 * 
	 * @param fee 卫生费实体（包含现有的billingPeriod信息）
	 * @param dto 编辑数据
	 * @return 最终费用金额
	 */
	private BigDecimal calculateFinalAmount(SanitationFee fee, SanitationFeeEditDTO dto) {
		BigDecimal baseAmount = dto.getAmount();

		// 从现有的billingPeriod字段解析月份区间
		String billingPeriod = fee.getBillingPeriod();
		if (billingPeriod != null && billingPeriod.contains("~")) {
			try {
				String[] monthRange = billingPeriod.split("~");
				if (monthRange.length == 2) {
					String startMonth = monthRange[0].trim();
					String endMonth = monthRange[1].trim();

					int monthCount = calculateMonthCount(startMonth, endMonth);

					if (monthCount > 0) {
						BigDecimal finalAmount = baseAmount.multiply(BigDecimal.valueOf(monthCount));
						log.info("时间段计费：单月费用 {} × {} 个月 = 总费用 {}, 月份区间: {}", baseAmount, monthCount, finalAmount,
								billingPeriod);
						return finalAmount;
					} else {
						log.warn("月份数量计算失败，使用单月费用: {}, 月份区间: {}", baseAmount, billingPeriod);
						return baseAmount;
					}
				}
			} catch (Exception e) {
				log.warn("解析月份区间失败，使用单月费用: {}, 月份区间: {}", baseAmount, billingPeriod, e);
				return baseAmount;
			}
		}

		// 默认使用单月费用
		log.info("使用单月费用: {}, 月份区间: {}", baseAmount, billingPeriod);
		return baseAmount;
	}

	/**
	 * 将实体转换为VO对象
	 * 
	 * @param fee 卫生费实体
	 * @return 卫生费VO对象
	 */
	private SanitationFeeVO convertToVO(SanitationFee fee) {
		SanitationFeeVO vo = new SanitationFeeVO();
		BeanUtils.copyProperties(fee, vo);

		// 通过区域地址Feign接口获取详细地址信息
		try {
			if (fee.getHouseholdId() != null) {
				AddressInfoDTO addressInfo = regionAddressFeignClient.getAddressByHouseholdId(fee.getHouseholdId());
				if (addressInfo != null) {
					// 设置房户号
					vo.setRoomNumber(addressInfo.getRoomNumber());

					// 设置社区信息
					vo.setCommunityName(addressInfo.getCommunityName());

					// 设置楼栋信息
					vo.setBuildingName(addressInfo.getBuildingName());

					// 设置单元信息
					vo.setUnitName(addressInfo.getUnitName());

					// 设置房户地址（使用完整地址）
					vo.setHouseholdAddress(addressInfo.getFullAddress());
				}
			}
		} catch (Exception e) {
			log.warn("获取区域地址信息失败，卫生费ID: {}, 房户ID: {}, 错误: {}", fee.getId(), fee.getHouseholdId(), e.getMessage());

			// 降级处理：使用原有的Feign接口获取基本信息
			try {
				if (fee.getHouseholdId() != null) {
					HouseholdInfoDTO household = regionDataFeignClient.getHouseholdById(fee.getHouseholdId());
					if (household != null) {
						vo.setRoomNumber(household.getRoomNumber());

						// 获取楼栋信息
						if (household.getBuildingId() != null) {
							BuildingInfoDTO building = regionDataFeignClient.getBuildingById(household.getBuildingId());
							if (building != null) {
								vo.setBuildingName(building.getBuildingName());

								// 获取社区信息
								if (building.getCommunityId() != null) {
									CommunityInfoDTO community = regionDataFeignClient
											.getCommunityById(building.getCommunityId());
									if (community != null) {
										vo.setCommunityName(community.getCommunityName());
									}
								}
							}
						}

						// 获取单元信息
						if (household.getUnitId() != null) {
							UnitInfoDTO unit = regionDataFeignClient.getUnitById(household.getUnitId());
							if (unit != null) {
								vo.setUnitName(unit.getUnitName());
							}
						}

						// 构建房户地址
						vo.buildHouseholdAddress();
					}
				}
			} catch (Exception fallbackException) {
				log.warn("降级获取区域信息也失败，卫生费ID: {}, 错误: {}", fee.getId(), fallbackException.getMessage());

				// 最终降级：设置默认值，确保不会因为地址信息获取失败而导致整个接口失败
				vo.setRoomNumber("未知房号");
				vo.setCommunityName("未知社区");
				vo.setBuildingName("未知楼栋");
				vo.setUnitName("未知单元");
				vo.setHouseholdAddress("地址信息获取失败");
			}
		}

		return vo;
	}

	/**
	 * 将实体列表转换为VO列表
	 * 
	 * @param feeList 卫生费实体列表
	 * @return 卫生费VO列表
	 */
	private List<SanitationFeeVO> convertToVOList(List<SanitationFee> feeList) {
		if (feeList == null || feeList.isEmpty()) {
			return new ArrayList<>();
		}

		return feeList.stream().map(this::convertToVO).collect(Collectors.toList());
	}

	/**
	 * 根据社区ID获取物业公司ID
	 * 
	 * @param communityId 社区ID
	 * @return 物业公司ID
	 */
	private Long getPropertyCompanyIdByCommunityId(Long communityId) {
		try {
			return propertyCompanyCommunityService.getPropertyCompanyIdByCommunityId(communityId);
		} catch (Exception e) {
			log.warn("获取社区对应的物业公司ID失败，社区ID: {}", communityId, e);
			return null;
		}
	}

	/**
	 * 根据物业公司ID和费用类型获取计费方式列表
	 * 
	 * @param propertyCompanyId 物业公司ID
	 * @param feeType           费用类型
	 * @return 计费方式列表
	 */
	private List<BillingMethod> getBillingMethodsByPropertyCompanyAndFeeTypeInternal(Long propertyCompanyId,
			String feeType) {
		try {
			// 调用计费方式服务获取计费方式列表
			List<BillingMethodVO> billingMethodVOs = billingMethodService
					.getBillingMethodsByPropertyCompanyAndFeeType(propertyCompanyId, feeType, null);

			// 将VO转换为实体对象
			List<BillingMethod> billingMethods = new ArrayList<>();
			for (BillingMethodVO vo : billingMethodVOs) {
				BillingMethod entity = new BillingMethod();
				entity.setId(vo.getId());
				entity.setPropertyCompanyId(vo.getPropertyCompanyId());
				entity.setFeeType(vo.getFeeType()); // 直接使用String类型
				entity.setBuildingTypeName(vo.getBuildingTypeName());
				entity.setMethodName(vo.getMethodName());
				entity.setMethodType(vo.getMethodType());
				entity.setUnitPrice(vo.getUnitPrice());
				entity.setFixedAmount(vo.getFixedAmount());
				entity.setTierConfig(vo.getTierConfig());
				entity.setDescription(vo.getDescription());
				entity.setStatus(vo.getStatus());
				entity.setSortOrder(vo.getSortOrder());
				billingMethods.add(entity);
			}

			return billingMethods;
		} catch (Exception e) {
			log.warn("获取计费方式列表失败，物业公司ID: {}, 费用类型: {}", propertyCompanyId, feeType, e);
			return new ArrayList<>();
		}
	}

	/**
	 * 根据楼栋建筑类型匹配计费方式
	 * 
	 * @param billingMethods 计费方式列表
	 * @param buildingType   楼栋建筑类型
	 * @param feeType        费用类型（用于验证）
	 * @return 匹配的计费方式
	 */
	private BillingMethod matchBillingMethodByBuildingType(List<BillingMethod> billingMethods, String buildingType,
			String feeType) {
		// 设置一个默认的先
		if (billingMethods.isEmpty()) {
			BillingMethod bm = new BillingMethod();
			bm.setFeeType(feeType);
			bm.setMethodName("默认卫生费计费方式");
			bm.setMethodType(1);
			bm.setFixedAmount(BigDecimal.valueOf(20.0));
			billingMethods.add(bm);
		}

		// 优先匹配特定建筑类型的计费方式
		for (BillingMethod method : billingMethods) {
			if (method.getBuildingTypeName() != null && method.getBuildingTypeName().equals(buildingType)
					&& feeType.equals(method.getFeeType())) {
				return method;
			}
		}

		// 如果没有匹配到特定建筑类型，返回适用于所有建筑类型的计费方式
		for (BillingMethod method : billingMethods) {
			if ((method.getBuildingTypeName() == null || method.getBuildingTypeName().trim().isEmpty())
					&& feeType.equals(method.getFeeType())) {
				return method;
			}
		}

		return null;
	}

	/**
	 * 转换支付方式字符串为整数值
	 * 
	 * @param paymentMethod 支付方式字符串
	 * @return 支付方式整数值，如果不支持则返回null
	 */
	private Integer convertPaymentMethodToCode(String paymentMethod) {
		if (paymentMethod == null || paymentMethod.trim().isEmpty()) {
			return null;
		}

		PaymentMethodEnum methodEnum = PaymentMethodEnum.fromValue(paymentMethod.trim());
		return methodEnum != null ? methodEnum.getCode() : null;
	}
	
	// ==================== 移动端专用方法实现 ====================
	
	@Override
	@Cacheable(value = "sanitationFee", key = "'my:' + #currentUserId + ':' + #current + ':' + #size + ':' + #paymentStatus + ':' + #billingPeriod", unless = "#result == null || #result.records.isEmpty()")
	public PageResult<SanitationFeeVO> getMySanitationFees(Integer current, Integer size, 
	                                                      Integer paymentStatus, String billingPeriod) {
		long startTime = System.currentTimeMillis();
		log.info("查询当前用户的卫生费账单开始，当前页：{}，每页大小：{}，缴费状态：{}，计费周期：{}", 
				current, size, paymentStatus, billingPeriod);
		
		try {
			// 参数验证
			if (current == null || current < 1) {
				current = 1;
			}
			if (size == null || size < 1 || size > 100) {
				size = 10;
			}
			
			// 获取当前用户ID
			Long currentUserId = SecurityUtils.getCurrentUserId();
			if (currentUserId == null) {
				log.warn("查询当前用户的卫生费账单失败，用户未登录");
				return createEmptyPageResult(current, size);
			}
			
			// 根据用户ID查询业主信息，获取关联的房户ID集合
			List<Long> householdIds = getHouseholdIdsByUserId(currentUserId);
			if (householdIds.isEmpty()) {
				log.info("用户未关联任何房户，用户ID: {}", currentUserId);
				return createEmptyPageResult(current, size);
			}
			
			// 构建查询条件
			LambdaQueryWrapper<SanitationFee> wrapper = new LambdaQueryWrapper<>();
			wrapper.in(SanitationFee::getHouseholdId, householdIds);
			
			// 添加其他查询条件
			if (paymentStatus != null) {
				wrapper.eq(SanitationFee::getPaymentStatus, paymentStatus);
			}
			if (billingPeriod != null && !billingPeriod.trim().isEmpty()) {
				wrapper.eq(SanitationFee::getBillingPeriod, billingPeriod);
			}
			
			// 只查询未删除的记录
			wrapper.eq(SanitationFee::getDeleted, 0);
			
			// 添加去重逻辑：按房户ID、计费周期去重
			wrapper.groupBy(SanitationFee::getHouseholdId, SanitationFee::getBillingPeriod);
			
			// 按创建时间倒序排列
			wrapper.orderByDesc(SanitationFee::getCreateTime);
			
			// 分页查询
			Page<SanitationFee> page = new Page<>(current, size);
			IPage<SanitationFee> pageResult = this.page(page, wrapper);
			
			// 转换为VO对象
			List<SanitationFeeVO> voList = new ArrayList<>();
			for (SanitationFee fee : pageResult.getRecords()) {
				SanitationFeeVO vo = convertToVO(fee);
				voList.add(vo);
			}
			
			// 构建分页结果
			PageResult<SanitationFeeVO> result = new PageResult<>();
			result.setRecords(voList);
			result.setTotal(pageResult.getTotal());
			result.setCurrent(current);
			result.setSize(size);
			result.setPages((int) pageResult.getPages());
			
			long responseTime = System.currentTimeMillis() - startTime;
			log.info("查询当前用户的卫生费账单成功，用户ID: {}, 总记录数: {}, 当前页记录数: {}, 耗时：{}ms", 
					currentUserId, result.getTotal(), voList.size(), responseTime);
			return result;
		} catch (Exception e) {
			long responseTime = System.currentTimeMillis() - startTime;
			log.error("查询当前用户的卫生费账单异常，耗时：{}ms", responseTime, e);
			return createEmptyPageResult(current, size); // 生产环境标准：返回空结果而不是抛出异常
		}
	}
	
	@Override
	@Cacheable(value = "sanitationFee", key = "'mobile_detail:' + #billId + ':' + #userId", unless = "#result == null")
	public SanitationFeeVO getSanitationFeeDetailForMobile(Long billId, Long userId) {
		long startTime = System.currentTimeMillis();
		log.info("获取卫生费详情开始（移动端），账单ID：{}，用户ID：{}", billId, userId);
		
		try {
			// 参数验证
			if (billId == null) {
				log.warn("获取卫生费详情失败，账单ID不能为空");
				return null;
			}
			
			// 查询账单信息
			SanitationFee fee = this.getById(billId);
			if (fee == null) {
				log.warn("卫生费账单不存在，账单ID: {}", billId);
				return null;
			}
			
			// 验证用户权限：判断当前用户是否为该房户的业主
			validateUserPermissionForFee(billId, userId);
			
			// 转换为VO对象
			SanitationFeeVO vo = convertToVO(fee);
			
			long responseTime = System.currentTimeMillis() - startTime;
			log.info("获取卫生费详情成功（移动端），账单ID: {}, 用户ID: {}, 费用金额: {}, 耗时：{}ms", 
					billId, userId, vo.getAmount(), responseTime);
			return vo;
		} catch (Exception e) {
			long responseTime = System.currentTimeMillis() - startTime;
			log.error("获取卫生费详情异常（移动端），账单ID: {}, 用户ID: {}, 耗时：{}ms", 
					billId, userId, responseTime, e);
			return null; // 生产环境标准：返回null而不是抛出异常
		}
	}
	
	@Override
	public void validateUserPermissionForFee(Long feeId, Long userId) {
		long startTime = System.currentTimeMillis();
		log.info("验证用户权限开始，费用ID：{}，用户ID：{}", feeId, userId);
		
		try {
			// 参数验证
			if (feeId == null) {
				log.warn("验证用户权限失败，费用ID不能为空");
				throw new BusinessException(ResultCode.PARAM_ERROR, "费用ID不能为空");
			}
			if (userId == null) {
				log.warn("验证用户权限失败，用户ID不能为空");
				throw new BusinessException(ResultCode.PARAM_ERROR, "用户ID不能为空");
			}
			
			// 查询费用信息
			SanitationFee fee = this.getById(feeId);
			if (fee == null) {
				log.warn("卫生费账单不存在，费用ID: {}", feeId);
				throw new BusinessException(ResultCode.DATA_NOT_FOUND, "卫生费账单不存在");
			}
			
			// 根据用户ID查询业主信息，获取关联的房户ID集合
			List<Long> householdIds = getHouseholdIdsByUserId(userId);
			if (householdIds.isEmpty()) {
				log.warn("用户未关联任何房户，用户ID: {}", userId);
				throw new BusinessException(ResultCode.PERMISSION_DENIED, "用户未关联任何房户");
			}
			
			// 验证用户是否有权限访问该费用记录
			if (!householdIds.contains(fee.getHouseholdId())) {
				log.warn("用户无权限访问该费用记录，费用ID: {}, 用户ID: {}, 房户ID: {}", 
						feeId, userId, fee.getHouseholdId());
				throw new BusinessException(ResultCode.PERMISSION_DENIED, "用户无权限访问该费用记录");
			}
			
			long responseTime = System.currentTimeMillis() - startTime;
			log.info("用户权限验证成功，费用ID: {}, 用户ID: {}, 耗时：{}ms", feeId, userId, responseTime);
		} catch (BusinessException e) {
			long responseTime = System.currentTimeMillis() - startTime;
			log.warn("用户权限验证失败，费用ID: {}, 用户ID: {}, 耗时：{}ms, 错误: {}", 
					feeId, userId, responseTime, e.getMessage());
			throw e; // 业务异常继续抛出
		} catch (Exception e) {
			long responseTime = System.currentTimeMillis() - startTime;
			log.error("用户权限验证异常，费用ID: {}, 用户ID: {}, 耗时：{}ms", 
					feeId, userId, responseTime, e);
			throw new BusinessException(ResultCode.OPERATION_FAILED, "权限验证异常"); // 系统异常转换为业务异常
		}
	}
	
	/**
	 * 根据用户ID查询业主信息，获取关联的房户ID集合
	 * 
	 * 严格按照《Java后端SpringBoot代码开发规范.md》Service规范：
	 * - 异常往外抛：移除try-catch异常处理，添加throws Exception声明
	 * - 详细的日志记录，包括开始、成功状态
	 * - 完善的权限验证和业务逻辑验证
	 * - 完整的JavaDoc注释
	 * 
	 * 业务逻辑：
	 * 1. 根据user_id查询sc_owner表，查询用户是否业主
	 * 2. 如果是业主，则根据sc_owner表中查出来的数据，再到sc_owner_household中查询，获取到业主关联的所有房户信息
	 * 
	 * @param userId 用户ID
	 * @return 房户ID集合
	 * @throws Exception 查询异常
	 */
	private List<Long> getHouseholdIdsByUserId(Long userId) throws Exception {
		log.info("开始查询用户关联的房户ID，用户ID: {}", userId);
		
		// 调用DataScopeService获取用户关联的房户ID集合
		// 该方法内部实现了完整的业务逻辑：
		// 1. 根据user_id查询sc_owner表，查询用户是否业主
		// 2. 如果是业主，则根据sc_owner表中查出来的数据，再到sc_owner_household中查询，获取到业主关联的所有房户信息
		List<Long> householdIds = dataScopeService.getOwnerHouseholdIds(userId);
		
		if (householdIds == null) {
			householdIds = Collections.emptyList();
		}
		
		log.info("查询用户关联的房户ID完成，用户ID: {}, 房户数量: {}", userId, householdIds.size());
		
		return householdIds;
	}
	
	@Override
	@Cacheable(value = "sanitationFee:household", key = "#householdId + ':' + #current + ':' + #size")
	public PageResult<SanitationFeeVO> getHouseholdSanitationFees(Long householdId, Integer current, Integer size) {
		long startTime = System.currentTimeMillis();
		log.info("获取房户卫生费列表开始，房户ID：{}，当前页：{}，每页大小：{}", householdId, current, size);
		
		try {
			// 参数验证
			if (householdId == null) {
				log.warn("获取房户卫生费列表失败，房户ID不能为空");
				return PageResult.empty(current, size);
			}
			if (current == null || current < 1) {
				current = 1;
			}
			if (size == null || size < 1) {
				size = 10;
			}
			
			// 创建分页对象
			Page<SanitationFee> page = new Page<>(current, size);
			
			// 构建查询条件
			LambdaQueryWrapper<SanitationFee> queryWrapper = new LambdaQueryWrapper<>();
			queryWrapper.eq(SanitationFee::getHouseholdId, householdId);
			queryWrapper.orderByDesc(SanitationFee::getCreateTime);
			
			// 执行分页查询
			IPage<SanitationFee> pageResult = this.page(page, queryWrapper);
			
			// 转换为VO对象
			List<SanitationFeeVO> voList = pageResult.getRecords().stream()
					.map(this::convertToVO)
					.collect(Collectors.toList());
			
			// 构建分页结果
			PageResult<SanitationFeeVO> result = new PageResult<>();
			result.setRecords(voList);
			result.setTotal(pageResult.getTotal());
			result.setCurrent(current);
			result.setSize(size);
			result.setPages((int) Math.ceil((double) pageResult.getTotal() / size));
			
			long responseTime = System.currentTimeMillis() - startTime;
			log.info("获取房户卫生费列表成功，房户ID：{}，总数：{}，耗时：{}ms", 
					householdId, result.getTotal(), responseTime);
			
			return result;
		} catch (Exception e) {
			long responseTime = System.currentTimeMillis() - startTime;
			log.error("获取房户卫生费列表异常，房户ID：{}，耗时：{}ms", householdId, responseTime, e);
			return PageResult.empty(current, size); // 生产环境标准：返回空分页结果而不是抛出异常
		}
	}
}
